package com.hyts.apidoc.swagger.handler;

import com.google.common.collect.Lists;
import com.hyts.apidoc.swagger.bean.*;
import com.hyts.apidoc.swagger.config.SwaggerConfig;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.Info;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.annotations.Tag;
import org.apache.commons.lang3.StringUtils;
import sun.reflect.CallerSensitive;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * project-name:coffice-toolbox
 * package-name:com.hyts.apidoc.swagger.handler
 * author:Libo/Alex
 * create-date:2019-05-17 11:04
 * email:liboware@gmail.com
 * description:此类主要用于: swagger
 */
public abstract class SwaggerAnnotationHandler {

    /**
     *
     * @return
     */
    public abstract String getPath(Method method);

    /**
     * Api注解服务
     * @param clazz
     */
    public SwaggerBean parseAnnotation(Class<?> clazz){
        //操作服务
        Annotation api = clazz.getAnnotation(SwaggerDefinition.class);
        SwaggerDefinition apiData =  (SwaggerDefinition)api;
        //构建swagger bean对象
        SwaggerBean swaggerBean = new SwaggerBean();
        //参数默认值
        swaggerBean.setBasePath(StringUtils.defaultIfBlank(apiData.basePath(),SwaggerConfig.DEFAULT_SWAGGER_BASE_PATH));
        //参数默认值
        swaggerBean.setSwagger(SwaggerConfig.DEFAULT_SWAGGER_VERSION);
        //参数默认值
        SwaggerDefinition.Scheme[] schemes = null;
        if(apiData.schemes()[0] == SwaggerDefinition.Scheme.DEFAULT){
            schemes = null;
        }
        swaggerBean.setSchemes(
                Stream.of(Optional.ofNullable(schemes).
                       orElse(SwaggerConfig.DEFAULT_SWAGGER_SCHEMES_ARRAY)).
                map(param->param.name()).collect(Collectors.toList())
        );
        //操作参数
        Tag[] tags = apiData.tags();
        if(StringUtils.isBlank(tags[0].description()) && StringUtils.isBlank(tags[0].name())){
            tags = null;
        }
        swaggerBean.setTags(
                Optional.ofNullable(tags).
                isPresent()?Stream.
                of(tags).
                map(param->new TagBean(param.name(),param.description())).
                collect(Collectors.toList()):
                SwaggerConfig.DEFAULT_SWAGGER_TAGS_ARRAY.entrySet().
                        parallelStream().map(param->new TagBean(param.getKey(),param.getValue())).collect(Collectors.toList()));
        //操作参数
        swaggerBean.setHost(StringUtils.defaultIfBlank(apiData.host(),SwaggerConfig.DEFAULT_SWAGGER_HOST));
        Method[] methods = clazz.getDeclaredMethods();
        List<PathBean> pathBeanList = Lists.newLinkedList();
        for(Method method:methods){
            if(method.getAnnotation(ApiOperation.class) != null){
                PathBean pathBean = buildPathBean(method);
                pathBeanList.add(pathBean);
            }
        }
        swaggerBean.setPaths(pathBeanList);
        swaggerBean = buildInfoBean(apiData,swaggerBean);
        return swaggerBean;
    }

    /**
     * 构建SwaggerBean对象
     * @param apiData
     * @return
     */
    private SwaggerBean buildInfoBean(SwaggerDefinition apiData,SwaggerBean swaggerBean){
        //info对象
        Info info = apiData.info();
        if(StringUtils.isBlank(info.title()) && StringUtils.isBlank(info.description())){
            info = null;
        }
        swaggerBean.setInfo(Optional.ofNullable(info).isPresent()?
                Stream.of(info).map(param->{
                    InfoBean infoBean =  new InfoBean();
                    infoBean.setDescription(param.description());
                    infoBean.setTitle(param.title());
                    infoBean.setVersion(param.version());
                    //license
                    LicenseBean licenseBean = new LicenseBean();
                    licenseBean.setName(param.license().name());
                    licenseBean.setUrl(param.license().url());
                    infoBean.setLicense(licenseBean);
                    //contact
                    ContactBean contactBean = new ContactBean();
                    contactBean.setEmail(param.contact().email());
                    return infoBean;
                }).findFirst().get():defaultInfoBean());
        return swaggerBean;
    }

    /**
     *
     * @return
     */
    private InfoBean defaultInfoBean(){
        InfoBean infoBean =  new InfoBean();
        infoBean.setDescription(SwaggerConfig.DEFAULT_SWAGGER_INFO_DESCRIPTION);
        infoBean.setTitle(SwaggerConfig.DEFAULT_SWAGGER_INFO_TITLE);
        infoBean.setVersion(SwaggerConfig.DEFAULT_SWAGGER_VERSION);
        //license
        LicenseBean licenseBean = new LicenseBean();
        licenseBean.setName(SwaggerConfig.DEFAULT_SWAGGER_LICENSE_NAME);
        licenseBean.setUrl(SwaggerConfig.DEFAULT_SWAGGER_LICENSE_URL);
        infoBean.setLicense(licenseBean);
        //contact
        ContactBean contactBean = new ContactBean();
        contactBean.setEmail(SwaggerConfig.DEFAULT_SWAGGER_INFO_CONTACT_EMAIL);
        infoBean.setContact(contactBean);
        return infoBean;
    }


    /**
     * 解析方法操作
     * @param method
     */
    private PathBean buildPathBean(Method method){
        Annotation api = method.getAnnotation(ApiOperation.class);
        ApiOperation apiData =  (ApiOperation)api;
        PathBean pathBean = new PathBean();
        pathBean.setMethod(StringUtils.defaultIfBlank(apiData.httpMethod(),
                SwaggerConfig.DEFAULT_SWAGGER_PATH_HTTP_METHODS[0]));
        pathBean.setTag(apiData.tags()[0]);
        pathBean.setDescription(apiData.notes());
        pathBean.setSummary(apiData.value());
        pathBean.setOperationId(apiData.nickname());
        pathBean.setProduces(Lists.newArrayList(StringUtils.defaultIfBlank(apiData.produces(),SwaggerConfig.DEFAULT_SWAGGER_PRODUCES)));
        pathBean.setConsumes(Lists.newArrayList(StringUtils.defaultIfBlank(apiData.consumes(),SwaggerConfig.DEFAULT_SWAGGER_CONSUMES)));
        pathBean.setPath(getPath(method));
        return pathBean;
    }

    public static void parseAnnotation(Parameter parameter){

    }


}
